package com.polaris.live.common

import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.Rect
import android.media.MediaDrm
import android.net.ConnectivityManager
import android.os.Build
import android.os.Build.VERSION
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.TextUtils
import android.text.format.Formatter
import android.view.Window
import android.webkit.WebSettings
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.PhoneUtils
import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.Utils
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.hjq.language.MultiLanguages
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.constant.CacheConst
import com.polaris.live.common.constant.ServerConfig
import com.polaris.live.common.manager.CoroutineScopeManager
import com.tencent.mmkv.MMKV
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.net.NetworkInterface
import java.util.Locale
import java.util.TimeZone
import java.util.UUID

/**
 * AppModule      这个类放这一些获取软件硬件的东西
 * 1是         0否
 *
 * @author Created by 半仙 on 2023/8/1/001 19:23
 */
@Suppress("unused")
object AppModule {

    lateinit var mApplication: Application

    private var isDebug = false

    fun isDebug() = isDebug

    fun isOpenLog() = ServerConfig.isDebug() || ServerConfig.isTestServer()

    private val packageInfo by lazy {
        mApplication.packageManager.getPackageInfo(mApplication.packageName, 0)
    }

    private var mGoogleAdId: String? = null
    private var mWidevineId: String? = null
    private var mAndroidId: String? = null

    private var mAppVersion: Int? = null

    fun init(application: Application) {
        mApplication = application

        GlobalScope.launch(CoroutineScopeManager.ioDispatcher) {
            try {
                mGoogleAdId = AdvertisingIdClient.getAdvertisingIdInfo(mApplication).id?.also {
                    val kv = MMKV.mmkvWithID(CacheConst.APP)
                    kv.encode(CacheConst.GOOGLE_AD_ID, it)
                }
            } catch (e: Exception) {
                null
            }
        }
        GlobalScope.launch(CoroutineScopeManager.ioDispatcher) {
            mWidevineId = try {
                //See https://stackoverflow.com/questions/16369818/how-to-get-crypto-scheme-uuid
                //You can find some UUIDs in the https://github.com/google/ExoPlayer source code
                val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
                val mediaDrm = MediaDrm(WIDEVINE_UUID)
                val widevineId = mediaDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)
                val sb = StringBuilder()
                for (aByte in widevineId) {
                    sb.append(String.format("%02x", aByte))
                }
                sb.toString()
            } catch (_: Throwable) {
                null
            }
        }
    }

    //应用类型
    fun getAppType(): Int {
        return AppConst.APP_TYPE
    }

    //获取应用版本
    fun getAppVersion(): Int {
        return mAppVersion ?: let {
            val packageInfo = mApplication.packageManager.getPackageInfo(mApplication.packageName, 0)
            packageInfo.versionCode.apply {
                mAppVersion = this
            }
        }
    }

    //获取编译版本
    fun getBuildVersion(): KotlinVersion {
        return KotlinVersion.CURRENT
    }

    //获取设备型号
    fun getOsModel(): String {
        return Build.MODEL
    }

    //获取系统版本
    fun getOsVersion(): String {
        return VERSION.RELEASE
    }

    //获取语言
    fun getLanguage(): String {
        return MultiLanguages.getSystemLanguage(appContext).language
    }

    /**
     * 获取语言和国家
     */
    fun getLanguageAndArea(): String {
        val country = MultiLanguages.getAppLanguage().country
        return if (TextUtils.isEmpty(country)) {
            MultiLanguages.getAppLanguage().language
        } else {
            MultiLanguages.getAppLanguage().language + "-" + country
        }
    }

    //获取唯一码
    fun getUniqueDeviceId(): String? {
        return CacheUtil.getUniqueId()
    }

    //获取唯一码，不能为空，实际上这里是无意义的
    fun requireUniqueDeviceId(): String {
        return getUniqueDeviceId() ?: getDeviceId()
    }

    //获取设备id
    fun getDeviceId(): String {
        return getAndroidDeviceId()
    }

    private fun getAndroidDeviceId(prefix: String = "", useCache: Boolean = true): String {
        if (!useCache) {
            return getUniqueDeviceIdReal(prefix)
        }
        return mAndroidId ?: synchronized(AppModule::class.java) {
            mAndroidId ?: let {
                val id = SPUtils.getInstance().getString("KEY_UDID_ANDROID", null)
                if (!id.isNullOrEmpty()) {
                    mAndroidId = id
                    return id
                }
                getUniqueDeviceIdReal(prefix)
            }
        }
    }

    private fun getUniqueDeviceIdReal(prefix: String): String {
        try {
            val androidId = DeviceUtils.getAndroidID()
            if (!androidId.isNullOrEmpty()) {
                return saveUdid(prefix + 2, androidId, "KEY_UDID_ANDROID")
            }
        } catch (_: Exception) {
        }

        //如果androidId无法获取则获取自定义生成的
        return SPUtils.getInstance().getString("KEY_UDID_UUID", null)
            ?: saveUdid(prefix + 9, "", "KEY_UDID_UUID")
    }

    private fun saveUdid(prefix: String, id: String, key: String): String {
        return getUdid(prefix, id).apply {
            mAndroidId = this
            SPUtils.getInstance().put(key, this)
        }
    }

    private fun getUdid(prefix: String, id: String): String {
        return if (id == "") {
            prefix + UUID.randomUUID().toString().replace("-", "")
        } else {
            prefix + UUID.nameUUIDFromBytes(id.toByteArray()).toString().replace("-", "")
        }
    }

    //是否平板
    fun isTablet(): Int {
        return try {
            if (DeviceUtils.isTablet()) {
                1
            } else {
                0
            }
        } catch (_: Throwable) {
            2
        }
    }

    //是否模拟器
    fun isEmulator(): Int {
        return try {
            if (DeviceUtils.isEmulator()) {
                1
            } else {
                0
            }
        } catch (_: Throwable) {
            2
        }
    }

    //是否使用vpn  1使用了   0没有
    fun checkVPN(): Int {
        return try {
            val cm =
                mApplication.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val b = cm.getNetworkInfo(ConnectivityManager.TYPE_VPN)?.isConnectedOrConnecting
            if (b == true) {
                1
            } else {
                0
            }
        } catch (_: Throwable) {
            2
        }
    }

    //vpn代理地址
    fun getProxyAddress(): String? {
        var port: String? = null
        if (checkVPN() == 1) {
            try {
                val en = NetworkInterface.getNetworkInterfaces()
                while (en.hasMoreElements()) {
                    val intf = en.nextElement()
                    val enumIpAddr = intf.inetAddresses
                    while (enumIpAddr.hasMoreElements()) {
                        val inetAddress = enumIpAddr.nextElement()
                        if (!inetAddress.isLoopbackAddress && intf.name.contains("tun")) {
                            port = Formatter.formatIpAddress(inetAddress.hashCode())
                        }
                    }
                }
            } catch (_: Throwable) {
            }
        }
        return port
    }

    //是否root  1是   0不是
    fun isAppRoot(): Int {
        return try {
            if (AppUtils.isAppRoot()) {
                1
            } else {
                0
            }
        } catch (_: Throwable) {
            2
        }
    }

    //是否开启debug  1是  0不是
    fun isAppDebug(): Int {
        return if (AppUtils.isAppDebug()) {
            1
        } else {
            0
        }
    }

    //是否允许模拟位置  1是  0不是
    fun isMockLocation(): Int {
        return try {
            val isOpen = Settings.Secure.getInt(
                mApplication.contentResolver,
                Settings.Secure.ALLOW_MOCK_LOCATION,
                0
            ) != 0
            if (isOpen) {
                1
            } else {
                0
            }
        } catch (_: Throwable) {
            2
        }
    }

    //获取手机时区
    fun getCurrentTimeZone(): String? {
        val timeZone = TimeZone.getDefault()
        val id = timeZone.id //获取时区id，如“Asia/Shanghai”
        val shotName = timeZone.getDisplayName(false, TimeZone.SHORT) //获取名字，如“GMT+08:00”

        return if (!TextUtils.isEmpty(id.toString())) {
            id.toString()
        } else {
            shotName
        }
    }

    //获取语言国家
    fun getLanguageCountry(): String {
        // 获取当前语言的国家代码  偶现
        val multiCountry = MultiLanguages.getSystemLanguage(appContext).country
        if (multiCountry.isNotEmpty()) {
            return multiCountry
        }
        val localeCountry = Locale.getDefault().country
        if (localeCountry.isNotEmpty()) {
            return localeCountry
        }
        val resourcesCountry = Resources.getSystem().configuration.locale.country
        if (resourcesCountry.isNotEmpty()) {
            return resourcesCountry
        }
        return getCountryBySim() ?: ""
    }

    private fun getCountryBySim(): String? {
        val manager = Utils.getApp().getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        val networkCountryIso = manager.networkCountryIso
        val simCountryIso = manager.simCountryIso?.uppercase(Locale.getDefault())
        return if (!TextUtils.isEmpty(simCountryIso)) {
            simCountryIso
        } else {
            networkCountryIso
        }
    }

    //获取mcc
    fun getMcc(): String? {
        return try {
            val networkOperator = getTelephonyManager()?.networkOperator
            if (networkOperator != null && networkOperator.length >= 3) {
                networkOperator.substring(0, 3)
            } else {
                null
            }
        } catch (_: Throwable) {
            null
        }
    }

    //获取mnc
    fun getMnc(): String? {
        return try {
            val networkOperator = getTelephonyManager()?.networkOperator
            if (networkOperator != null && networkOperator.length >= 3) {
                networkOperator.substring(3)
            } else {
                null
            }
        } catch (_: Throwable) {
            null
        }
    }

    //获取网络地区
    fun getNetworkIsoCountry(): String? {
        return try {
            getTelephonyManager()?.networkCountryIso
        } catch (_: Throwable) {
            null
        }
    }

    //获取sim卡地区
    fun getSimIsoCountry(): String? {
        return try {
            getTelephonyManager()?.simCountryIso
        } catch (_: Throwable) {
            null
        }
    }

    private fun getTelephonyManager(): TelephonyManager? {
        return mApplication.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
    }

    //获取网络运营商名称
    fun getNetworkName(): String? {
        return try {
            NetworkUtils.getNetworkOperatorName()
        } catch (_: Throwable) {
            null
        }
    }

    fun getNumber(): String? {
        return try {
            PhoneUtils.getDeviceId()
        } catch (_: Throwable) {
            null
        }
    }

    fun getVersionName(): String {
        return try {
            packageInfo.versionName
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    /**
     * 获取应用程序名称
     */
    fun appName(): String {
        return try {
            val labelRes = packageInfo.applicationInfo.labelRes
            mApplication.resources.getString(labelRes)
        } catch (_: Throwable) {
            ""
        }
    }

    /**
     * 获取应用包名
     */
    fun packageName(): String {
        return try {
            packageInfo.packageName
        } catch (_: Throwable) {
            ""
        }
    }

    /**
     * 获取手机型号
     *
     * @return 手机型号
     */
    fun phoneType(): String {
        return Build.MODEL ?: ""
    }

    /**
     * 获取当前手机系统版本号
     *
     * @return 系统版本号
     */
    fun systemVersion(): Int {
        return VERSION.SDK_INT
    }

    /**
     * 获取安卓UUID
     */
    fun getMyUUID(): String? {
        return if (!TextUtils.isEmpty(CacheUtil.getuuid())) {
            val uuid = CacheUtil.getuuid()?.replace("-", "")
            uuid
        } else {
            val uuid = UUID.randomUUID()
            val uniqueId = uuid.toString().replace("-", "")
            CacheUtil.setuuid(uniqueId)
            uniqueId
        }
    }

    /**
     * 获取数字版权id
     */
    fun getWidevineId(): String? {
        return mWidevineId
    }

    /**
     * 获取gaid
     */
    fun getGoogleAdId(): String? {
        return mGoogleAdId ?: let {
            val kv = MMKV.mmkvWithID(CacheConst.APP)
            kv.decodeString(CacheConst.GOOGLE_AD_ID).apply {
                mGoogleAdId = this
            }
        }
    }

    fun getChannel(): String {
        val noChannel = "no channel"
        return kotlin.runCatching {
            mApplication.packageManager?.getApplicationInfo(
                mApplication.packageName, PackageManager.GET_META_DATA
            )?.let {
                it.metaData["APP_CHANNEL"] as? String? ?: noChannel
            } ?: noChannel
        }.fold(
            { it },
            { noChannel }
        )
    }

    /**
     * 获取屏幕宽高, first 是宽  second 是高
     */
    fun getScreenInfo(): Pair<Int, Int> {
        return Pair(
            Resources.getSystem().displayMetrics.widthPixels,
            Resources.getSystem().displayMetrics.heightPixels
        )
    }

    /**
     * 返回 WebView 使用的默认用户代理
     */
    fun getUserAgent(): String {
        return WebSettings.getDefaultUserAgent(mApplication)
    }

    /**
     * 获取状态栏高度
     */
    @SuppressLint("PrivateApi", "InternalInsetResource")
    fun getStatusBarHeight(window: Window, context: Context): Int {
        val localRect = Rect()
        window.decorView.getWindowVisibleDisplayFrame(localRect)
        var mStatusBarHeight = localRect.top
        if (0 == mStatusBarHeight) {
            kotlin.runCatching {
                val localClass = Class.forName("com.android.internal.R\$dimen")
                val localObject = localClass.newInstance()
                localClass.getField("status_bar_height")[localObject]?.toString()?.toInt()?.let {
                    mStatusBarHeight = context.resources.getDimensionPixelSize(it)
                }
            }
        }
        if (0 == mStatusBarHeight) {
            val resourceId = context.resources.getIdentifier(
                "status_bar_height",
                "dimen",
                "android"
            )
            if (resourceId > 0) {
                mStatusBarHeight = context.resources.getDimensionPixelSize(resourceId)
            }
        }
        return mStatusBarHeight
    }

    /**
     * 查看是否有谷歌服务
     */
    fun checkGoogleServices(): Boolean {
        val googleApiAvailability = GoogleApiAvailability.getInstance()
        val resultCode = googleApiAvailability.isGooglePlayServicesAvailable(mApplication)
        return resultCode == ConnectionResult.SUCCESS
    }
}